from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
 

# Create your views here.
# 1. 类视图必须直接或者间接继承于django.views.View
# 2. 在django的类视图中，所有提供给外界用户访问的视图方法名必须是 http请求动作的小写名称.
#    也就是说，方法名只能是 get, post, put, patch, delete ...
# 3. 使用类视图，可以有效的减少路由绑定的代码
#    3.1 可以直接通过视图方法名就可以达到限制客户端访问当前视图方法的http请求。
#    3.2 客户端访问对应的URL地址就会来到视图类中，访问这个地址所使用http请求，就是将来视图类自动执行的方法
#    3.3 有了类视图，我们可以把多个函数视图中原来的公共代码封装到一块进行调用，有利于代码复用。

# 4. 注意：同一个视图中，方法名不能出现重复！！！

from django.views import View
from django.http.response import HttpResponse, JsonResponse

import json


class UserView(View):
    # 类视图中的公共方法/公共属性
    def ret(self, data):
        print(self.request.method) # 在类视图中，不仅可以通过视图方法中的参数，接收路由传递过来的请求对象，还可以通过self.request来或路由转发过来的请求对象
        return HttpResponse(data)

    def get(self,request):
        """只允许通过get请求访问,建议编写读取数据的页面,一般例如:首页,列表页,详情页"""
        # 视图中的视图方法里面的代码，与原来的函数视图中的代码，是一模一样的。原来怎么写，现在还是怎么写。
        return self.ret("hello, get")

    def post(self,request):
        """只允许通过post请求访问,一般用于上传,添加数据的页面"""
        return self.ret("hello, post")

    def put(self,request):
        """只允许通过put请求访问,一般用于修改,更新数据的页面"""
        return self.ret("hello, put")

    def patch(self,request):
        """只允许通过patch请求访问,一般用于修改,更新数据的页面"""
        return self.ret("hello, patch")

    def delete(self,request):
        """只允许通过delete请求访问,一般用于处理删除数据的页面"""
        return self.ret("hello, delete")


class GoodsView(View):

    def ret(self,data):
        return JsonResponse(data,safe=False)

    def post(self,request):
        data = {"id": 1, "name": "小熊饼干", "price": "5.40"}
        return self.ret(data)

    def get(self,request):
        data = [
            {"id": 2, "name": "小熊饼干", "price": "5.40"},
            {"id": 3, "name": "大熊饼干", "price": "15.40"},
        ]
        return self.ret(data)

    def put(self,requsest):
        data = {"id": 1, "name": "小熊面包", "price": "5.40"}
        return self.ret(data)

    def delete(self,request):
        data = {"msg": "ok"}
        return self.ret(data)
  
    def patch(self,request):
        data = {"msg": "ok"}
        return self.ret(data)


""""
自定义视图基类
视图基类，可以专门一些公共的属性或者方法。
提供给将来开发的时候，用于完成特定业务的。这也可以封装成一个个视图基类，然后让具体的视图类直接继承，就不需要重写编写这些代码了
"""

class APIView(View):
    # 可以把没有参数的类方法，转换成普通属性来调用
    @property # 在你的代码片段中，@property 被用于 data 方法，这意味着你可以像访问属性一样访问 data，而不需要调用 data()。
    def data(self):
        """用于接受并装换json数据成字典"""
        ct = self.request.META.get("CONTENT_TYPE")
        # print(ct)
        if "multipart/form-data" in ct:
            """表单上传数据[允许上传文件]"""
            return self.request.POST.dict()
        if "application/x-www-form-urlencoded" in ct:
            """表单上传数据"""
            return self.request.POST.dict()
        if "application/json" in ct:
            try:
                data = json.loads(self.request.body)
                return data
            except Exception:
                return None


# 使用 method_decorator 来装饰类中的所有相关方法，而不是每个方法单独装饰 免除对每个方法单独使用 @csrf_exempt
@method_decorator(csrf_exempt, name='dispatch')
class HomeView(APIView):
    def post(self, request):
        print(self.data)
        return HttpResponse("ok")
    def put(self, request):
        print(self.data)
        return HttpResponse("ok")
    def patch(self, request):
        print(self.data)
        return HttpResponse("ok")


@method_decorator(csrf_exempt, name='dispatch') # apipost 测试开启
class FormView(View):
    def get(self,request):
        """注册页面""" 
        return render(request, "cbv_Form.html")
    
    def post(self,request):
        """注册信息提交"""
        print(request.POST)
        return HttpResponse("ok")


# 相关扩展

# 在django提供的视图类View使用中，还提供了一些视图子类和视图基类。
# 不过这块内容需要结合django的数据库操作才可以使用，所以我们后面再来学习。
# 视图子类是django为了方便开发者快速提供基于不同http请求视图而提供的。
# ​
# from django.views.generic import ListView,DetailView,CreateView,UpdateView,DeleteView
# ​
# ListView:   列表视图，可以通过get请求访问，用于展示列表数据，内置了分页功能    
# DetailView：详情视图，可以通过get请求访问，用于展示单个数据
# CreateView：添加视图，可以通过get/post请求访问，用于添加单个数据
# UpdateView：更新视图，可以通过get/post请求访问，用于更新单个数据
# DeleteView：删除视图，可以通过get请求访问，用于删除单个数据


















